/**
 * Copyright 2011 FeedDreamwork SIG
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.feeddreamwork.processors;

import java.util.*;

import org.feeddreamwork.*;
import org.feeddreamwork.feed.*;

public class FeedGenerator {
	private FeedInfo feedInfo;

	public FeedGenerator(FeedInfo feedInfo) {
		Utils.throwIfNull(feedInfo);
		this.feedInfo = feedInfo;
	}

	public FeedResult generate() throws FeedProcessException {
		FeedContext context = new FeedContext(feedInfo);
		boolean isFinalStage = false;
		List<String> commands = feedInfo.getProcessors();
		List<FeedProcessor> processors = new ArrayList<FeedProcessor>();
		for (String command : commands) {
			FeedProcessor processor = FeedProcessorBuilder
					.getProcessor(command);
			if (processor != null)
				processors.add(processor);
		}

		for (int i = 0; i < processors.size(); i++) {
			FeedProcessor processor = processors.get(i);
			if (context.isCancelled())
				return context.getFeedResult();
			if (!isFinalStage && processor instanceof FinalFeedProcessor) {
				for (int j = i; j < processors.size(); j++) {
					if (processors.get(j) instanceof FinalFeedProcessor)
						((FinalFeedProcessor) processors.get(j))
								.prepareBeforeFinalProcess(context);
					else
						throw new FeedProcessException();
				}
				if (context.isCancelled())
					return context.getFeedResult();
				finalProcess(context);
				isFinalStage = true;
				if (context.isCancelled())
					return context.getFeedResult();
			}

			processor.process(context);
		}
		
		if (!isFinalStage)
			finalProcess(context);
		return context.getFeedResult();
	}

	private void finalProcess(FeedContext context) {
		FeedBuilder feedBuilder = FeedBuilders.getFeedBuilder(
				context.getFeed(), context.getFeedId(), context.getFeedInfo()
						.getTargetType());
		FeedResult newResult = new FeedResult(context.getFeedId(),
				feedBuilder.getMIMEType());
		newResult.setContent(feedBuilder.build());
		newResult.updateHash();

		FeedResultRepository feedResultRepo = new FeedResultRepository();
		try {
			FeedResult oldResult = (FeedResult) FeedResultCache.get(context.getFeedId());
			
			if (oldResult == null)
				oldResult = feedResultRepo.getFeedResult(context.getFeedId());
			
			if (oldResult != null && oldResult.getHash() == newResult.getHash()) {
				context.cancel();
				context.setFeedResult(oldResult, feedBuilder);
				return;
			} else {
				newResult.setContent(feedBuilder.addUpdatedTime(
						newResult.getContent(), new Date()));
				feedResultRepo.saveObject(newResult);
				context.setFeedResult(newResult, feedBuilder);
			}
		} finally {
			if (feedResultRepo != null)
				feedResultRepo.close();
		}
	}
}
